package com.self.cloudmall.pms.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.self.cloudmall.common.dto.AttrsDto;
import com.self.cloudmall.common.dto.ElasticSkuDto;
import com.self.cloudmall.common.dto.FullReductionDto;
import com.self.cloudmall.common.dto.SpuBoundDto;
import com.self.cloudmall.common.enumm.ProductStateEnum;
import com.self.cloudmall.common.utils.R;
import com.self.cloudmall.pms.client.CouponClient;
import com.self.cloudmall.pms.client.SearchClient;
import com.self.cloudmall.pms.client.WareStockClient;
import com.self.cloudmall.pms.entity.*;
import com.self.cloudmall.pms.mapper.SpuInfoMapper;
import com.self.cloudmall.pms.service.*;
import com.self.cloudmall.pms.utils.PageUtils;
import com.self.cloudmall.pms.utils.Query;
import com.self.cloudmall.pms.vo.BaseAttrVo;
import com.self.cloudmall.pms.vo.SkuVo;
import com.self.cloudmall.pms.vo.SpuSaveVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Slf4j
@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoMapper, SpuInfoEntity> implements SpuInfoService {

    @Autowired
    private SpuInfoDescService spuInfoDescService;
    @Autowired
    private SpuImagesService spuImagesService;
    @Autowired
    private ProductAttrValueService productAttrValueService;
    @Autowired
    private AttrService attrService;
    @Autowired
    private SkuInfoService skuInfoService;
    @Autowired
    private CouponClient couponClient;
    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;
    @Autowired
    private WareStockClient wareStockClient;
    @Autowired
    private SearchClient searchClient;
    
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveSpuSaveVo(SpuSaveVo spuInfo) throws Exception {
        //保存spu基本信息pms_spu_info
        SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
        assembleSpuInfoEntity(spuInfoEntity,spuInfo);
        this.save(spuInfoEntity);
        //保存spu描述图片pms_spu_info_desc
        List<String> decript = spuInfo.getDecript();
        if (!CollectionUtils.isEmpty(decript)){
            SpuInfoDescEntity descEntity = new SpuInfoDescEntity();
            assembleDecript(descEntity,decript,spuInfoEntity);
            spuInfoDescService.save(descEntity);
        }
        //保存spu图片集pms_spu_images
        List<String> images = spuInfo.getImages();
        if (!CollectionUtils.isEmpty(images)){
            List<SpuImagesEntity> imagesEntities = Lists.newArrayList();
            assembleSpuImages(imagesEntities,images,spuInfoEntity);
            if (!CollectionUtils.isEmpty(imagesEntities)){
                spuImagesService.saveBatch(imagesEntities);
            }
        }
        //保存spu规格参数pms_product_attr_value
        List<BaseAttrVo> baseAttrs = spuInfo.getBaseAttrs();
        if (!CollectionUtils.isEmpty(baseAttrs)){
            List<ProductAttrValueEntity> productAttrValueEntities = Lists.newArrayList();
            assembleProductAttrValues(productAttrValueEntities,baseAttrs,spuInfoEntity);
            if (!CollectionUtils.isEmpty(productAttrValueEntities)){
                productAttrValueService.saveBatch(productAttrValueEntities);
            }
        }
        //保存sku基本信息pms_sku_info
        //保存sku图片pms_sku_images
        //保存sku销售属性pms_sku_sale_attr_value
        List<SkuVo> skus = spuInfo.getSkus();
        if (!CollectionUtils.isEmpty(skus)){
            skuInfoService.batchSaveSkuRelation(skus,spuInfoEntity);
        }
        //保存sku优惠、满减信息cloud-sms库==>sms_sku_ladder/sms_sku_full_reduction/sms_spu_bounds
        SpuBoundDto boundDto = new SpuBoundDto();
        BeanUtils.copyProperties(spuInfo.getBounds(),boundDto);
        boundDto.setSpuId(spuInfoEntity.getId());
        R boundR = couponClient.save(boundDto);
        if (!boundR.isSuccess()){
          log.error("商品SPU积分保存失败：{}",boundR.get("msg"));
          throw new Exception("商品SPU积分保存失败,spuID="+spuInfoEntity.getId());
        }

        if (!CollectionUtils.isEmpty(skus)){
            List<FullReductionDto> dtos = assembleFullReductionDto(skus,spuInfoEntity);
            if (!CollectionUtils.isEmpty(dtos)){
                R addR = couponClient.batchAdd(dtos);
                if (!addR.isSuccess()){
                    log.error("商品满减保存失败：{}",boundR.get("msg"));
                    throw new Exception("商品满减保存失败,spuID="+spuInfoEntity.getId());
                }
            }
        }
        return true;
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> queryWrapper = new QueryWrapper<>();
        LambdaQueryWrapper<SpuInfoEntity> lambda = queryWrapper.lambda();
        String key = (String) params.get("key");
        if (StringUtils.isNotEmpty(key)){
            lambda.and(w -> w.eq(SpuInfoEntity::getId,key).or().like(SpuInfoEntity::getSpuName,key));
        }
        String status = (String) params.get("status");
        if (StringUtils.isNotEmpty(status)){
            lambda.eq(SpuInfoEntity::getPublishStatus,status);
        }
        String brandId = (String) params.get("brandId");
        if (StringUtils.isNotEmpty(brandId) && !"0".equals(brandId)){
            lambda.eq(SpuInfoEntity::getBrandId,Long.parseLong(brandId));
        }
        String catelogId = (String) params.get("catelogId");
        if (StringUtils.isNotEmpty(catelogId) && !"0".equals(catelogId)){
            lambda.eq(SpuInfoEntity::getCatalogId,Long.parseLong(catelogId));
        }
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public R spuUp(Long spuId) {
        //由spuId查询所有sku
        List<SkuInfoEntity> skus = skuInfoService.querySkusBySpuId(spuId);
        if (CollectionUtils.isEmpty(skus)){
            return R.error("商品对应的sku不存在");
        }
        //4.查询sku可以搜索的商品规格
        //因为每个sku的商品规格都是一样，所以放在循环外边只查一次
        List<ProductAttrValueEntity> attrValueEntities = productAttrValueService.queryEnableSearchAttrValueBySpuId(spuId);
        if (CollectionUtils.isEmpty(attrValueEntities)){
            return R.error("商品规格参数不存在");
        }
        List<AttrsDto> attrsDtos = attrValueEntities.stream().map(x -> {
            AttrsDto attr = new AttrsDto();
            BeanUtils.copyProperties(x, attr);
            return attr;
        }).collect(Collectors.toList());
        //1.发送远程调用，查询是否有库存
        List<Long> skuIds = skus.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        Map<Long, Boolean> stockMap = null;
        try {
            R<Map<Long, Boolean>> r = wareStockClient.hasStock(skuIds);
            if (!r.isSuccess()){
                return R.error("远程查询库存发生异常");
            }
            stockMap = r.getData();
        } catch (Exception e) {
            log.error("远程查询库存发生异常:{}",e);
            return R.error("远程查询库存发生异常");
        }

        //遍历skus，填充ElasticSkuDato
        Map<Long, Boolean> finalStockMap = stockMap;
        List<ElasticSkuDto> elasticSkuDtos = skus.stream().map(x -> {
            ElasticSkuDto skuDato = new ElasticSkuDto();
            BeanUtils.copyProperties(x, skuDato);
            skuDato.setSkuPrice(x.getPrice());
            skuDato.setSkuImg(x.getSkuDefaultImg());
            //1.发送远程调用，查询是否有库存
            skuDato.setHasStock(finalStockMap.get(x.getSkuId()+""));
            //2.热评份默认为0
            skuDato.setHotScore(0L);
            //3.填充品牌和分类名称
            BrandEntity brandEntity = brandService.getById(x.getBrandId());
            if (brandEntity != null){
                skuDato.setBrandName(brandEntity.getName());
                skuDato.setBrandImg(brandEntity.getLogo());
            }
            CategoryEntity categoryEntity = categoryService.getById(x.getCatalogId());
            if (categoryEntity != null){
                skuDato.setCatalogName(categoryEntity.getName());
            }
            //4.查询sku可以搜索的商品规格
            skuDato.setAttrs(attrsDtos);
            return skuDato;
        }).collect(Collectors.toList());
        //调用search服务，保存商品到es
        try {
            R result = searchClient.productAdd(elasticSkuDtos);
            if (result.isSuccess()){
               //更新商品状态上架
                SpuInfoEntity spuInfoEntity = new SpuInfoEntity();
                spuInfoEntity.setId(spuId);
                spuInfoEntity.setUpdateTime(new Date());
                spuInfoEntity.setPublishStatus(ProductStateEnum.UP.getCode());
               this.updateById(spuInfoEntity);
            }else{
                //调用失败，重复调用，接口幂等性
                //feign 默认是负载均衡调用的，默认最大重试5次；
                //es put数据，如果同一个id，就是update，否则是新增，保证数据不重复；
            }
        } catch (Exception e) {
           log.error("商品保存到es异常:{}",e);
        }
        return R.ok();
    }

    @Override
    public R getSpuInfo(Long skuId) {
        SkuInfoEntity skuInfo = skuInfoService.getById(skuId);
        if (skuId == null){
            return R.error("商品sku不存在");
        }
        SpuInfoEntity spuInfoEntity = this.getBaseMapper().selectById(skuInfo.getSpuId());
        if (spuInfoEntity == null){
            return R.error("商品spu不存在");
        }
        return R.ok().setData(spuInfoEntity);
    }

    private List<FullReductionDto> assembleFullReductionDto(List<SkuVo> skus, SpuInfoEntity spuInfoEntity) {
        return skus.stream().filter(x ->
                ((x.getFullPrice() != null && x.getFullPrice().compareTo(BigDecimal.ZERO) > 0)
         || x.getFullCount() > 0))
                .map(x -> {
            FullReductionDto reductionDto = new FullReductionDto();
            BeanUtils.copyProperties(x,reductionDto);
            return reductionDto;
        }).collect(Collectors.toList());
    }

    private void assembleProductAttrValues(List<ProductAttrValueEntity> productAttrValueEntities, List<BaseAttrVo> baseAttrs, SpuInfoEntity spuInfoEntity) {
        baseAttrs.stream().forEach(x ->{
            ProductAttrValueEntity pav = new ProductAttrValueEntity();
            pav.setSpuId(spuInfoEntity.getId());
            pav.setAttrId(x.getAttrId());
            pav.setAttrValue(x.getAttrValues());
            pav.setQuickShow(x.getShowDesc());
            AttrEntity attrEntity = attrService.getById(x.getAttrId());
            if (attrEntity != null){
                pav.setAttrName(attrEntity.getAttrName());
            }
            productAttrValueEntities.add(pav);
        });
    }

    private void assembleSpuImages(List<SpuImagesEntity> imagesEntities, List<String> images, SpuInfoEntity spuInfoEntity) {
        images.stream().forEach(x ->{
            if (StringUtils.isNotEmpty(x)){
                SpuImagesEntity imagesEntity = new SpuImagesEntity();
                imagesEntity.setSpuId(spuInfoEntity.getId());
                imagesEntity.setImgUrl(x);
                imagesEntities.add(imagesEntity);
            }
        });
    }

    private void assembleDecript(SpuInfoDescEntity descEntity, List<String> decript,SpuInfoEntity spuInfoEntity) {
        descEntity.setSpuId(spuInfoEntity.getId());
        descEntity.setDecript(StringUtils.join(decript,","));
    }


    private void assembleSpuInfoEntity(SpuInfoEntity spuInfoEntity, SpuSaveVo spuInfo) {
        BeanUtils.copyProperties(spuInfo,spuInfoEntity);
        Date date = new Date();
        spuInfoEntity.setCreateTime(date);
        spuInfoEntity.setUpdateTime(date);
    }

}